import {
    BrowserType,
    ImportBookmarkType,
    SyncMethod,
    UrlOpenType,
    onedrive,
    SyncServiceSettingObj, ConfigObj
} from "@/utils/constants";
import {getBrowserType} from "@/utils/utils";
import {ref, Ref, shallowRef, ShallowRef, toRaw} from "vue";


class SyncServiceSetting {
    /**
     * 启用
     */
    enable: ShallowRef<boolean, boolean> = shallowRef<boolean>(false);
    /**
     * 是否可以启用
     */
    canEnable: ShallowRef<boolean, boolean> = shallowRef<boolean>(false);
    /**
     * 秘钥
     */
    _token: ShallowRef<string | undefined | null> = shallowRef();
    /**
     * 同步方式
     */
    syncMethod: ShallowRef<string> = shallowRef(SyncMethod.none);
    /**
     * 定时同步时间
     */
    cronSyncTime: ShallowRef<number | null> = shallowRef(null);

    constructor(
        enable: boolean = false,
        token?: string | undefined | null,
        syncMethod: string = SyncMethod.none,
        cronSyncTime: number | null = null,
    ) {
        this.enable.value = enable;
        this._token.value = token;
        this.syncMethod.value = syncMethod;
        this.cronSyncTime.value = cronSyncTime;
        this.checkCanEnable();
        // console.log("初始化同步服务完成", this);
    }

    /**
     * 获取token
     */
    get token(): ShallowRef<string | undefined | null> {
        console.log("get token", this._token);
        return this._token;
    }

    /**
     * 设置token
     * @param token
     */
    set token(token: string | undefined | null) {
        console.log("set token", token);
        this._token.value = token;
        this.checkCanEnable();
    }

    checkCanEnable() {
        this.canEnable.value = !!this._token.value;
        if (!this.canEnable) {
            this.enable.value = false;
        }
    }

    toObj() {
        // console.log("SyncServiceSetting toObj this", this);
        return {
            enable: this.enable.value,
            token: this._token.value,
            syncMethod: this.syncMethod.value,
            cronSyncTime: this.cronSyncTime.value,
        }
    }

    /**
     * 从object转成同步服务设置
     * @param obj
     */
    static fromObject(obj: SyncServiceSettingObj): SyncServiceSetting {
        return new SyncServiceSetting(
            obj.enable,
            obj.token,
            obj.syncMethod,
            obj.cronSyncTime,
        );
    }

    fromSyncServiceSetting(obj: SyncServiceSetting | SyncServiceSettingObj) {
        if (obj instanceof SyncServiceSetting) {
            this.enable.value = obj.enable.value;
            this._token.value = obj._token.value;
            this.syncMethod.value = obj.syncMethod.value;
            this.cronSyncTime.value = obj.cronSyncTime.value;
        }
        else {
            this.enable.value = obj.enable ? obj.enable : this.enable.value;
            this._token.value = obj.token;
            this.syncMethod.value = obj.syncMethod ? obj.syncMethod : this.syncMethod.value;
            this.cronSyncTime.value = obj.cronSyncTime ? obj.cronSyncTime : this.cronSyncTime.value;
        }
        this.checkCanEnable();
    }
}


const defaultSyncServiceSettingMap = (): Record<string, SyncServiceSetting> => {
    return {
        [onedrive]: new SyncServiceSetting(),
    }
};


/**
 * 配置
 */
class Config {
    /**
     * 当收藏夹搜索关键词为空时，是否折叠收藏夹
     */
    isCollapsedWhenBookmarkTreeNullSearch: ShallowRef<boolean, boolean> = shallowRef(false);
    /**
     * 浏览器类型
     */
    browserType: BrowserType = BrowserType.chrome;
    /**
     * 是否保存书签页面状态
     */
    isStoreBookmarkExpandStatus: ShallowRef<boolean, boolean> = shallowRef(false);
    /**
     * 是否显示固钉
     */
    isShowAffix: ShallowRef<boolean, boolean> = shallowRef(false);
    /**
     * 语言
     */
    language: ShallowRef<string> = shallowRef("zh-cn");
    /**
     * 链接打开方式
     */
    urlOpenType: ShallowRef<string> = shallowRef(UrlOpenType.newTab);
    /**
     * 收藏夹导入方式
     */
    importBookmarkType: ShallowRef<string> = shallowRef(ImportBookmarkType.merge);
    /**
     * 同步服务
     */
    syncServiceSettingMap: Ref<Record<string, SyncServiceSetting>> = ref(defaultSyncServiceSettingMap());
    /**
     * 监听书签变化
     */
    watchBookmarkChange: ShallowRef<boolean, boolean> = shallowRef(true);


    constructor(
        isCollapsedWhenBookmarkTreeNullSearch: boolean = false,
        browserType?: BrowserType,
        isStoreBookmarkExpandStatus: boolean = true,
        isShowAffix: boolean = true,
        language: string = "zh-cn",
        urlOpenType: string = UrlOpenType.newTab,
        importBookmarkType: string = ImportBookmarkType.merge,
        syncServiceSettingMap: Record<string, SyncServiceSetting> = defaultSyncServiceSettingMap(),
        watchBookmarkChange: boolean = true,
    ) {
        this.isCollapsedWhenBookmarkTreeNullSearch.value = isCollapsedWhenBookmarkTreeNullSearch;
        this.browserType = browserType || getBrowserType();
        this.isStoreBookmarkExpandStatus.value = isStoreBookmarkExpandStatus;
        this.isShowAffix.value = isShowAffix;
        this.language.value = language;
        this.urlOpenType.value = urlOpenType;
        this.importBookmarkType.value = importBookmarkType;
        this.syncServiceSettingMap.value = syncServiceSettingMap;
        this.watchBookmarkChange.value = watchBookmarkChange;
        // console.log("初始化配置完成", this);
    }

    fromConfig(config: Config) {
        this.isCollapsedWhenBookmarkTreeNullSearch.value = config.isCollapsedWhenBookmarkTreeNullSearch.value;
        this.browserType = config.browserType;
        this.isStoreBookmarkExpandStatus.value = config.isStoreBookmarkExpandStatus.value;
        this.isShowAffix.value = config.isShowAffix.value;
        this.language.value = config.language.value;
        this.urlOpenType.value = config.urlOpenType.value;
        this.importBookmarkType.value = config.importBookmarkType.value;
        this.syncServiceSettingMap.value = config.syncServiceSettingMap.value;
        this.watchBookmarkChange.value = config.watchBookmarkChange.value;
    }

    /**
     * 转成object
     */
    toObj(): ConfigObj {
        const syncServiceSettingMap = Object.entries(toRaw(this.syncServiceSettingMap.value));
        const syncServiceSettingObj = Object.fromEntries(syncServiceSettingMap.map(([key, value]) => [key, value.toObj()]));
        // console.log("syncServiceSettingObj", syncServiceSettingObj);
        return {
            isCollapsedWhenBookmarkTreeNullSearch: this.isCollapsedWhenBookmarkTreeNullSearch.value,
            browserType: this.browserType,
            isStoreBookmarkExpandStatus: this.isStoreBookmarkExpandStatus.value,
            isShowAffix: this.isShowAffix.value,
            language: this.language.value,
            urlOpenType: this.urlOpenType.value,
            importBookmarkType: this.importBookmarkType.value,
            syncServiceSettingMap: syncServiceSettingObj,
            watchBookmarkChange: this.watchBookmarkChange.value,
        };
    }

    /**
     * 从object转成配置
     * @param obj
     */
    static fromObject(obj: ConfigObj): Config {
        const newSyncServiceSettingMap: Record<string, SyncServiceSetting> = defaultSyncServiceSettingMap();
        if (obj.syncServiceSettingMap) {
            for (const key in obj.syncServiceSettingMap) {
                const settingObj = obj.syncServiceSettingMap[key];
                if (!newSyncServiceSettingMap[key]) {
                    // todo
                    // newSyncServiceSettingMap[key] = SyncServiceSetting.fromObject(settingObj);
                }
                else {
                    newSyncServiceSettingMap[key].fromSyncServiceSetting(settingObj);
                }
            }
        }
        return new Config(
            obj.isCollapsedWhenBookmarkTreeNullSearch,
            obj.browserType,
            obj.isStoreBookmarkExpandStatus,
            obj.isShowAffix,
            obj.language,
            obj.urlOpenType,
            obj.importBookmarkType,
            newSyncServiceSettingMap,
            obj.watchBookmarkChange,
        );
    }
}


/**
 * 序列化配置
 * @param config
 */
function dumpConfigJSON(config: Config): string {
    return JSON.stringify(config.toObj());
}


/**
 * 反序列化配置
 * @param configJson
 */
function loadConfigJSON(configJson: string): Config {
    let obj = JSON.parse(configJson);
    return Config.fromObject(obj);
}


export {Config, dumpConfigJSON, loadConfigJSON, SyncServiceSetting};
